// 实现在线用户管理模块

#ifndef __ONLINE_USER__HPP
#define __ONLINE_USER__HPP

#include "util.hpp"
#include "Log.hpp"
#include <unordered_map>
#include <mutex>

class OnlineUserManage
{
private:
    /*为帮助函数提供传参方便*/
    typedef std::unordered_map<uint64_t, wsserver_t::connection_ptr> server_t;

    /*检查帮助函数*/
    bool IsInHelper(const uint64_t id, const std::string &type, const server_t &find_type)
    {
        /*find*/
        auto it = find_type.find(id);
        if (it == find_type.end())
        {
            ERRLOG("%lu user is not in game %s ! ", id, type.c_str());
            return false;
        }
        return true;
    }

    /*退出帮助函数*/
    void ExitHelper(const uint64_t id, const std::string &type, server_t &find_type)
    {

        if (!IsInHelper(id, type, find_type))
        {
            ERRLOG("%lu user is not in game %s ! ", id, type.c_str());
            return;
        }

        find_type.erase(id);
        DBGLOG("%lu online user exit the game %s ! ", id, type.c_str());
    }

    
    /*获取连接帮助函数*/
    wsserver_t::connection_ptr GetConnectionHelper(const uint64_t id, const std::string &type, const server_t &find_type)
    {
        auto it = find_type.find(id);
        if (it == find_type.end())
        {
            ERRLOG("%lu user get connection from %s failed ! ", id, type.c_str());
            return wsserver_t::connection_ptr();
        }
        return it->second;
    }

public:
    OnlineUserManage() = default;

    ~OnlineUserManage() = default;

    /*用户进入大厅(上线) -- 提供增加在线用户功能,为大厅匹配对战做准备*/
    void EnterGameHall(const uint64_t id, const wsserver_t::connection_ptr &conn)
    {
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        _game_hall.insert(std::make_pair(id, conn));
        DBGLOG("%lu user online and enter the game hall ! ", id);
    }

    /*用户进入房间 -- 提供增加在线用户功能 , 为房间对战/聊天做准备*/
    void EnterGameRoom(const uint64_t id, const wsserver_t::connection_ptr &conn)
    {
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        _game_room.insert(std::make_pair(id, conn));
        DBGLOG("%lu user online and enter the game room ! ", id);
    }

    /*用户退出大厅(下线) -- 提供删除用户功能*/
    void ExitGameHall(const uint64_t id)
    {
        std::string type = "hall";
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        ExitHelper(id, type, _game_hall);
    }

    /*用户退出房间 -- 提供删除用户功能*/
    void ExitGameRoom(const uint64_t id)
    {
        std::string type = "room";
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        ExitHelper(id, type, _game_room);
    }

    /*在大厅 , 可以进行匹配*/
    bool IsInGameHall(const uint64_t id)
    {

        std::string type = "hall";
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        return IsInHelper(id, type, _game_hall);
    }

    /*在房间 , 可以进行对战 / 聊天*/
    bool IsInGameRoom(const uint64_t id)
    {
        std::string type = "room";
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        return IsInHelper(id, type, _game_room);
    }

    /*获取游戏大厅连接 -- 可以通过连接进行发送消息等(进行通信)*/
    /*wsserver_t::connection_ptr 为连接指针*/
    wsserver_t::connection_ptr GetConnectionFromHall(const uint64_t id)
    {
        std::string type = "hall";
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        return GetConnectionHelper(id, type, _game_hall);
    }

    /*获取游戏房间连接 -- 可以通过连接进行发送消息等(进行通信)*/
    wsserver_t::connection_ptr GetConnectionFromRoom(const uint64_t id)
    {
        std::string type = "room";
        std::unique_lock<std::mutex> lock(_mutex); /*构建锁管理器*/
        return GetConnectionHelper(id, type, _game_room);
    }

private:
    // 通过映射建立用户与 websocket 的连接管理 :

    /*建立游戏大厅用户ID和 websocket的连接管理的映射 -- 提供大厅匹配通信*/
    std::unordered_map<uint64_t, wsserver_t::connection_ptr> _game_hall;
    /*建立游戏房间用户ID和 websocket的连接管理的映射 -- 提供房间对战/聊天通信*/
    std::unordered_map<uint64_t, wsserver_t::connection_ptr> _game_room;
    /*锁 , 保证线程安全*/
    std::mutex _mutex;
};
#endif

/**
 * 以上功能除了Get函数外均进行了测试 , 可正常使用 ! (Get函数测试需要加业务)
 * 本模块主要是对在线用户管理 , 只有在线用户才可以匹配对战 , 只有在线用户才可以进入房间对战/聊天
 * 提供功能 :
 * 1. EnterGameHall -- 用户进入大厅即 : 上线 , 登录成功 , 此时可以进匹配玩家了
 * 2. EnterGameRoom -- 用户进入房间即 : 匹配玩家成功 , 在该房间双方进行对战 , 聊天
 * 3. ExitGameHall  -- 用户退出大厅即 : 用户正式下线,不在玩了,删除该用户信息
 * 4. ExitGameRoom  -- 用户退出房间即 : 用户退出当场对战 , 还可以匹配其它玩家
 * 5. 其余辅助功能见上 ^^^^
 *
 * 为什么要设计这个模块呢 ??
 * 1. 因为这个项目核心功能 : 玩家匹配 , 玩家对战 , 玩家聊天 ,只有在线用户才能参与匹配、进入房间对战，且对战过程中需要实时同步棋子 , 聊天等
 * 2. 项目基于 WebSocket 长连接实现实时通信(因为需要服务器主动推送消息)，而每个在线用户都会持有一个独立的 WebSocket 连接（connection_ptr)
 * 3. 在这个连接中 , 当需要给用户发送消息时(如:匹配成功,落棋信息等)时 , 必须通过该用户ID快速找到对应的连接然后通过服务器转发
 * 4. 所设计该模块的目的有两个 :
 *     1. 通过用户ID可以找到对应的 websocket 连接进行通信执行不同的业务逻辑
 *     2. 方便统一管理在线用户 , 用户上线,下线自动管理
 *
 * 怎么设计的 ??
 * 1 . 采用哈希表进行映射 , 可以以O(1)的时间复杂度进行 find查找 , 效率高 .
 * 2 . 保证多线程下的线程安全 , 有可能在多线程下多个客户端都要操作访问哈希表 , 为了避免并发执行导致数据不一致问题的线程不安全 , 所以采用加锁保证了 .
 * 3 . 因为代码中有很多重复部分 , 所以我提供了帮助函数对代码优化 , 减少代码冗余
 */